package com.pangu.utils;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pangu.exception.BizException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author Linbizhao
 * @description 通用转换工具类，针对pojo(do、vo、dto)类对象进行处理的工具类
 * @date 2025-11-13
 */
public class ConvertUtils {

    static final String GET = "get";
    static final String SET = "set";


    public static <T> T convert(Object srcEntity, Class<T> targetVoClass) {
        T targetVO = null;
        try {
            targetVO = targetVoClass.newInstance();
        } catch (Exception e) {
            throw new BizException("接口异常");
        }
        Map<String, Method> srcMethodMap = listMethodMap(srcEntity, GET);
        Map<String, Method> targetMethodMap = listMethodMap(targetVO, SET);
        giveValue(srcEntity, targetVO, srcMethodMap, targetMethodMap);
        return targetVO;
    }

    /**
     * 批量转换
     *
     * @param srcEntities     源对象集合
     * @param targetVoClass   目标对象类型
     * @param <T>             目标对象类型
     * @return List<T>
     */
    public static <T> List<T> convertBatch(List<? extends Object> srcEntities, Class<T> targetVoClass) {
        List<T> list = new ArrayList<T>();
        for (Object srcEntity : srcEntities) {
            T vo = convert(srcEntity, targetVoClass);
            list.add(vo);
        }
        return list;
    }

    /**
     * 分页转换
     *
     * @param srcPage         源分页对象
     * @param targetVoClass   目标对象类型
     * @param <T>             目标对象类型
     * @return Page<T>
     */
    public static <T> Page<T> convertPage2Page(IPage<? extends Object> srcPage, Class<T> targetVoClass){
        Page<T> voPage=new Page<T>();
        List<? extends Object> records = srcPage.getRecords();
        List<T> convertBatchList = convertBatch(records,targetVoClass);
        voPage.setCurrent(srcPage.getCurrent());
        voPage.setPages(srcPage.getPages());
        voPage.setSize(srcPage.getSize());
        voPage.setTotal(srcPage.getTotal());
        voPage.setRecords(convertBatchList);
        return voPage;
    }


    /**
     * 筛选出object中所有的包含subMethodName方法，并放入以截取了subMethodName字符后的方法名为key，方法对象为value放入到MAP
     *
     * @param object        待遍历对象
     * @param subMethodName 子方法名称
     * @return Map<String, Method>
     */
    private static Map<String, Method> listMethodMap(Object object, String subMethodName) {
        Method[] methods = object.getClass().getMethods();
        Map<String, Method> methodMap = new HashMap<String, Method>();
        for (Method method : methods) {
            if (method.getName().startsWith(subMethodName)) {
                methodMap.put(method.getName().substring(subMethodName.length()), method);
            }
        }
        return methodMap;
    }

    /**
     * 遍历DO中所有的get方法，把每次遍历的方法和VO中的方法比较，如果方法的属性名一致（这里get方法没有get字符串，set方法没有set字符串）
     * 则先执行DO中的get方法获取DO中相应属性的返回值，然后通过把返回值当成参数，执行VO中对应的set方法
     *
     * @param srcEntity        源对象
     * @param targetVO         目标对象
     * @param srcMethodMap     存放源对象get方法的map集合
     * @param targetMethodMap  存放目标对象set方法的map集合
     */
    private static void giveValue(Object srcEntity, Object targetVO, Map<String, Method> srcMethodMap, Map<String, Method> targetMethodMap) {
        Iterator<Map.Entry<String, Method>> it = srcMethodMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Method> row = it.next();
            String methodName = row.getKey();
            Method srcMethod = row.getValue();
            Method targetMethod = targetMethodMap.get(methodName);
            if (targetMethod != null) {
                try {
                    Object returnObject = srcMethod.invoke(srcEntity);
                    if (returnObject != null) {
                        targetMethod.invoke(targetVO, returnObject);
                    }
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    throw new BizException("对象拷贝赋值异常");
                }
            }
        }
    }
}
